home *** CD-ROM | disk | FTP | other *** search
/ SPACE 1 / SPACE - Library 1 - Volume 1.iso / program / 569 / gemfst17 / gemxtend.doc < prev    next >
Text File  |  1992-06-01  |  29KB  |  594 lines

  1.  
  2. **************************************************************************
  3. *
  4. * GEMXTEND.DOC - Descriptions of extensions made to GEM bindings since
  5. *                the original TOS 1.0 release.
  6. *
  7. *  09/02/91    - v1.7
  8. *                Added new function vgd_detect() to detect GDOS.
  9. *
  10. *  07/18/91    - v1.6 (Has it really been a year since the last release?)
  11. *                Added new VDI function vdicall(), which allows you to
  12. *                "roll your own" binding to a VDI function that's not
  13. *                directly supported in vdifast.a.  This ought to please
  14. *                all the GDOS-using folks.  This is documented at the
  15. *                very end of this doc file.
  16. *
  17. *  06/29/90    - v1.5
  18. *                Added function v_gchar() to output a single text char.
  19. *
  20. *  05/26/90    - v1.4
  21. *                Included documentation on the new calling standard,
  22. *                and the bindings that currently support it:
  23. *                   evnx_multi()
  24. *                   frmx_center()
  25. *                   winx_get()
  26. *                   winx_calc()
  27. *
  28. *  09/06/89    - v1.3
  29. *                This document is new with this release, and contains
  30. *                revisions through TOS 1.4.
  31. **************************************************************************
  32.  
  33. This document is divided into two sections.  Section 1 documents the 
  34. changes and additions Atari has made to the GEM routines in TOS.  Section 2 
  35. documents alternate calling standards to the existing functions.  These
  36. alternate bindings provide more efficient ways to call AES functions.
  37.  
  38.  
  39. **************************************************************************
  40. *
  41. * Section 1 - Changes Atari has made to GEM/TOS.
  42. *
  43. **************************************************************************
  44.  
  45. This section describes extensions Atari has made to TOS/GEM since the
  46. original TOS 1.0 operating system.  When Atari adds new VDI/AES functions,
  47. appropriate bindings will be created and documented here.  Note that some
  48. of the functions listed here have been available since TOS 1.0, but Atari
  49. neglected to document them.  The title bar for each function lists the
  50. first TOS version that supported the function.  Other functions have 
  51. backwards compatibility built into the GEMFAST binding so that they will 
  52. work correctly on all TOS versions (these are noted in the title bars too).
  53.  
  54. *--------------------------------------------------------------------------
  55. * About TOS 1.4...
  56. *--------------------------------------------------------------------------
  57.  
  58.  The TOS 1.4 pre-release notes contain documentation for the following:
  59.  
  60.    form_error    form_alert    shel_write    shel_get    shel_put  
  61.    fsel_exinput  wind_new
  62.  
  63.  Of these, the form_error/alert and shel_???? docs seem to be just a 
  64.  clarification of the docs without any functional changes.
  65.  
  66.  The wind_new and fsel_exinput functions are new with TOS 1.4.
  67.  
  68. ;-------------------------------------------------------------------------
  69. ; wind_new                    TOS 1.4
  70. ;-------------------------------------------------------------------------
  71.  
  72.   void wind_new();
  73.  
  74.   The 'wind_new' function is for doing a major cleanup after a GEM 
  75.   application.  It closes & deletes all windows, flushes all the windows'
  76.   buffers (of redraw msgs, I presume), clears the wind_update flag, and
  77.   restores ownership of the mouse to the system (END_MCTRL I presume). The
  78.   documentation is not clear on whether this function should be used by
  79.   an application that wants to shut down everything quickly, or whether it
  80.   is intended for a shell's use in cleaning up after an application exits.
  81.   I tend to suspect the latter, and I think this function was developed 
  82.   because shell writers all begged Atari to provide something that could
  83.   clean up after an application the way the desktop does.
  84.  
  85. ;-------------------------------------------------------------------------
  86. ; fsel_exinput                TOS 1.4 (binding compatible with 1.0 and up)
  87. ;-------------------------------------------------------------------------
  88.  
  89.   Full 1.4 emulation...
  90.  
  91.   status = fsel_exinput(in_path, in_sel, &exitbtn, prompt_text);
  92.   
  93.    (status and exitbtn are 16-bit ints, others are char *).
  94.    
  95.  This routine is functionally equivelent to fsel_input, except that it
  96.  also allows you to specify a prompt string of up to 30 characters to be
  97.  displayed along with the file selector.  While the function is new with
  98.  TOS 1.4, the AESFAST bindings support it in all versions via a routine
  99.  which checks the AES version number and simulates the actions of
  100.  fsel_exinput by using fsel_input and objc_draw.  If running under
  101.  TOS 1.4, the system will display your prompt text in place of the words
  102.  'FILE SELECTOR' inside the fsel box.  If running under pre-TOS 1.4, the
  103.  simulation routines place the prompt text in a box which appears 
  104.  between the menu bar and the fsel box.
  105.  
  106.  Other TOS 1.4 changes to the fsel routines that this routine supports 
  107.  via simulation when running on pre-TOS 1.4 systems...
  108.  
  109.   - The file selector now allows you to edit the pathname and hit RETURN
  110.     without exiting the dialog.  If you edit the filename and hit <CR>,
  111.     you will exit as if you clicked on OK.
  112.   - If the initial pathname has a leading '\', it will be appended to the
  113.     end of the current default drive and path, and the entire resulting
  114.     string will be returned if the user exits via OK or <CR>.
  115.   - The current default drive and path are preserved, and the contents
  116.     of the current DTA are preserved.  Only the default path on the 
  117.     default drive is saved with the simulation software. If the user
  118.     changes devices during file selection, the default path on all devices
  119.     may  be changed except for the device that was the default when 
  120.     fsel_exinput was called.
  121.  
  122.   The executable code for the fsel_exinput binding is big -- about 800
  123.   bytes.  Also, it uses about 350 bytes of stack space during the call.
  124.   Still, having a prompted file selector that works correctly on all
  125.   machines will lend a touch of class to your application (IMHO).
  126.  
  127.   Note that all of the above fsel ehancements which are supported by the
  128.   simulation on pre-TOS 1.4 systems are supported ONLY if you call
  129.   fsel_exinput; if you call fsel_input on a pre-1.4 system the default
  130.   path et. al. will behave as they always have. (Hint: USE exinput).
  131.  
  132. ;-------------------------------------------------------------------------
  133. ; fsel_smallexinput           TOS 1.4 (binding compatible with 1.0 and up)
  134. ;-------------------------------------------------------------------------
  135.  
  136.   Prompting emulation only...
  137.  
  138.   This function has calling parameters identical to fsel_exinput() (see
  139.   above), but it's behavior (return values, etc) is identical to that of
  140.   fsel_input() (the original).  This function will call the real 'exinput'
  141.   routine if on TOS 1.4, but if on an earlier version it emulates only the
  142.   prompting of 'exinput', it does not save the path or DTA, or handle <CR>
  143.   correctly, or any of the other nice TOS 1.4 features.  On the other hand,
  144.   it's only half as big as the full emulator for fsel_exinput(), so it's
  145.   handy for accessories and other small-memory applications.  (It will add
  146.   about 450 bytes to your program, as opposed to 800).        
  147.   
  148.   I'd like to recommend that you do not code calls to fsel_smallexinput()
  149.   directly in your program.  Instead, just code fsel_exinput(), and at the
  150.   top of your C source, code:
  151.   
  152.     #define fsel_exinput fsel_smallexinput
  153.  
  154.   and let the C compiler handle the rest for you.  This ought to keep your
  155.   code compatible many years into the future...
  156.  
  157. ;-------------------------------------------------------------------------
  158. ; fsel_14input              TOS 1.4 (binding compatible with 1.0 and up)
  159. ;-------------------------------------------------------------------------
  160.  
  161.   No emulation.
  162.  
  163.   This function has calling parameters identical to fsel_exinput() (see
  164.   above).  However, it makes no attempt to emulate any of the 1.4 exinput
  165.   features.  Basically, if running on TOS 1.4, fsel_exinput is called.  If
  166.   running on a pre-1.4 system, the prompt string is thrown away, and the
  167.   normal file selector is called.  This binding is very small compared to
  168.   other (emulation mode) exinput bindings.
  169.   
  170.   Again, it is best to access this function through a #define statement:
  171.   
  172.     #define fsel_exinput fsel_14input
  173.  
  174. | This function was added with v1.4.
  175.  
  176. ;-------------------------------------------------------------------------
  177. ; shel_get / shel_put         TOS 1.0
  178. ;-------------------------------------------------------------------------
  179.  
  180.   status = shel_get(char *bufadr, int buflen)
  181.   status = shel_put(char *bufadr, int buflen)
  182.   
  183.           These functions read and write the desktop's internal buffer
  184.           which holds a copy of the DESKTOP.INF file.  The buffer holds
  185.           an exact image of the file, in plain ASCII text.  If 'status'
  186.           is returned as zero, an error occurred.  The Atari docs say that
  187.           the buffer should never exceed 1024 bytes, but I've been told
  188.           that it *can* in fact exceed this length.
  189.  
  190. ;-------------------------------------------------------------------------
  191. ; form_keybd                  TOS 1.0
  192. ;-------------------------------------------------------------------------
  193.  
  194.   keyret = form_keybd(tree, object, nxtobject, thechar, &nxtobject, &thechar);
  195.   
  196.      (All values are 16-bit words, except 'tree', which is OBJECT *).
  197.      
  198.      The form_keybd routine acts as a filter on character input.
  199.      When it  recognizes a control  character,  it processes
  200.      it and zeroes the keyboard word.  Other chararacters can be
  201.      passed on to objc_edit to be inserted in the editable object.  
  202.      If the routine returns a zero, a default object is selected (<CR>).
  203.      (Hints:  If 'nxtobject' is not equal to 'object' after this call,
  204.      form_keybd() has detected a TAB or ARROW key to move to the next
  205.      edit field, so call objc_edit(..., EDEND) for the current field,
  206.      as long as nxtobject is non-zero.  If 'thechar' comes back non-zero,
  207.      pass it to objc_edit(..., EDCHAR).  If this doesn't make sense, get
  208.      the Tim Oren articles and make your own interpretations.)
  209.  
  210. ;-------------------------------------------------------------------------
  211. ; form_button                 TOS 1.0
  212. ;-------------------------------------------------------------------------
  213.  
  214.   btnret = form_button(tree, object, clicks, &nxtobject);
  215.   
  216.      (All values are 16-bit words, except 'tree', which is OBJECT *).
  217.           
  218.      I can't tell you as much about this one.  This routine handles an
  219.      already-occurred mouse button event.  It handles changing the 
  220.      selected object into reverse video.  It (presumably) handles radio
  221.      buttons. 'object' is the index of the object the mouse is over, so
  222.      I presume have have to call objc_find() first to get this. 'nxtobject'
  223.      is the new selected object index.  If the routine returns a zero,
  224.      a default or exit object was selected.
  225.  
  226.  
  227. **************************************************************************
  228. *
  229. * Section 2 - An alternate calling standard, and supporting bindings...
  230. *
  231. **************************************************************************
  232.  
  233. BACKGROUND
  234.  
  235. The calling standard for AES functions defined and documented by DRI was
  236. defined for ease of use in C programming, but it does not lend itself to
  237. particularly efficient code generation.  For example, the wind_get() call
  238. can be used to return many different types of values, so DRI defined the
  239. function as taking pointers to 4 separate output fields.  However, one of 
  240. most common functions for wind_get() is to return information about window
  241. rectangles; the values are returned in typical GRECT order. 
  242.  
  243. In the old days, a call of this type was often coded as:
  244.  
  245.     wind_get(wi_handle, WF_CURRXYWH, &x, &y, &w, &h);
  246.     
  247. As GEM coding techniques have become more sophisticated, people have found
  248. that it makes more sense to keep xywh values in GRECT structures instead of
  249. in discrete variables.  This leads to the rather cumbersome construct:
  250.  
  251.     wind_get(wi_handle, WF_CURRXYWH, 
  252.                 &windrect.g_x, &windrect.g_y,
  253.                 &windrect.g_w, &windrect.g_h);
  254.                 
  255. When ideally, one would prefer to code:
  256.  
  257.     wind_get(wi_handle, WF_CURRXYWH, &windrect);
  258.     
  259. This makes a huge difference in runtime performance.  When the binding for
  260. the original wind_get() routine is called, it has no idea whether discrete
  261. (possibly discontiguous) addresses are passed, so it must build a temporary
  262. output array on the stack in which the AES can pass return values.  Upon 
  263. return from the AES, the binding must copy each of the four return values
  264. back to the caller's memory, using the 4 individual pointers specified.
  265. Using the alternate calling standard, the binding can simply pass the AES
  266. the GRECT pointer specified in the call, and the AES can place the returned
  267. values directly into the caller's memory, avoiding intermediate arrays.
  268. Also, the C compiler only has to stack one address when setting up the call.
  269.  
  270. STANDARDS
  271.  
  272. Because it is not possible to have one function name to handle both types
  273. of calling standards, I have choosen to implement the alternate bindings
  274. using similar names, with an 'x' to indicate it is one of the extended
  275. bindings.  Thus, wind_get() would be called when discrete addresses are
  276. passed, and winx_get() would be called when a single pointer is passed.
  277.  
  278. There will be a certain amount of schizophrenia in the alternate binding
  279. standards.  Some functions (such as evnx_multi) will take all input and
  280. output values in a single consolidated structure.  Others will pass 
  281. discrete input values, but take the return values in a structure, or
  282. vice versa.  I will try to use common sense when making such decisions;
  283. what I want to avoid is the VDI mess.  With VDI calls, you have to load
  284. *everything* into an array, even when it doesn't seem to make sense to 
  285. do so.  I think VDI coding is very tedious for this reason, and I'm going
  286. to try to avoid that with the alternate AES bindings.
  287.  
  288. As an aside:  I've heard rumours that Tim Oren defined an entire alternate
  289. calling structure for the AES under the name GEMX.  Unfortunately, I can't
  290. find out anything about it except that it 'may exist'.  Therefore, nothing
  291. in my alternate calling standards are going to correspond to his, except
  292. by accident.  If anybody has more info on GEMX, I'd love to learn about it.
  293.  
  294. IMPLEMENTATION
  295.  
  296. I had planned to write the entire set of alternate bindings and release
  297. them as GemFast v2.0.  I've been planning that for months, and it isn't
  298. working out.  Therefore, beginning with v1.4, I'm releasing things as I 
  299. go.  As of 1.4, there are only a couple of these extended bindings 
  300. available.
  301.  
  302. The C-source version of the AESFAST utilities (GEMFUTxx.ARC) contains 
  303. versions of the extended AES routines (evnx_multi, et. al.), to provide
  304. code compatibility.  The C versions of these functions do not provide the
  305. speed of the assemblerized versions in AESFAST.A, but they also do not add
  306. more than a few bytes to the size of your program.
  307.  
  308. X-STRUCTURES
  309.  
  310. Where custom data structures are needed by an alternate binding, the
  311. structures will be documented with the binding(s) that use them.  All such
  312. structures are defined in the GEMFAST.H header file.
  313.  
  314. ;-------------------------------------------------------------------------
  315. ; evnx_multi    - Alternate for evnt_multi.
  316. ;-------------------------------------------------------------------------
  317.  
  318.     int evnx_multi(XMULTI *xm);
  319.     
  320.     This binding takes a single parm, a pointer to an XMULTI structure.  It 
  321.     returns an integer, which is a bit mask of events which occurred (the
  322.     same value returned by evnt_multi).  This mask is also returned in 
  323.     the mwhich element of the XMULTI structure.
  324.     
  325.     All of the values normally passed to evnt_multi are included in the
  326.     XMULTI structure.  All of the output values are returned in the XMULTI
  327.     structure, including messages in the message buffer, which is the 1st
  328.     eight words of the XMULTI structure.
  329.     
  330.     The XMULTI structure is defined as follows:
  331.     
  332.         typedef struct xmulti {         
  333.             int     msgbuf[8];          /* Message buffer               */
  334.             int     mflags;             /* Mask of events to wait for   */
  335.             int     mbclicks,           /* Button clicks to wait for    */
  336.                     mbmask,             /* Which buttons to wait for    */
  337.                     mbstate;            /* Button state to wait for     */
  338.             int     mm1flags;           /* M1 rect: wait for in/out flag*/
  339.             GRECT   mm1rect;            /* M1 rect: xywh coordinates    */
  340.             int     mm2flags;           /* M2 rect: wait for in/out flag*/
  341.             GRECT   mm2rect;            /* M2 rect: xywh coordinates    */
  342.             int     mtlocount,          /* Timer count low value        */
  343.                     mthicount;          /* Timer count high value       */
  344.             int     mwhich,             /* Mask of events that occurred */
  345.                     mmox,               /* Mouse x at time of event     */
  346.                     mmoy,               /* Mouse y at time of event     */
  347.                     mmobutton,          /* Mouse buttons at event       */
  348.                     mmokstate,          /* Keystate at event            */
  349.                     mkreturn,           /* Key pressed at event         */
  350.                     mbreturn;           /* Times buttons was clicked    */
  351.         } XMULTI;                       
  352.  
  353.     It is most efficient to code the XMULTI structure as a local variable
  354.     of the function that uses it, although it can be defined as a global
  355.     or static variable.  A simple, typical multi-handler might look like:
  356.     
  357.     multi()
  358.     {
  359.         XMULTI  xm;
  360.         int     events
  361.         
  362.         /* 
  363.          * set up static portions of xm structure...
  364.          */
  365.  
  366.         xm.mflags = MU_TIMER | MU_MESAG | MU_BUTTON;
  367.         
  368.         xm.tlocount = 1000;         /* 1 second     */
  369.         xm.thicount = 0;            /* timer value  */
  370.  
  371.         xm.mbclicks = 1;            /* wait for single  */
  372.         xm.mbmask   = 1;            /* click of left    */
  373.         xm.mbstate  = 1;            /* button           */
  374.  
  375.         while (1) {
  376.  
  377.             events = evnx_multi(&xm);
  378.             
  379.             if (events & MU_BUTTON) {
  380.                 handle_button(xm.mox, xm.moy);
  381.             }
  382.  
  383.             if (events & MU_TIMER) {
  384.                 handle_timeout();
  385.             }
  386.  
  387.             if (events & MU_MESAG) {
  388.                 switch(xm.msgbuf[0]) {
  389.                   case WM_REDRAW:
  390.                     do_redraw(xm.msgbuf[3], &xm.msgbuf[4]);
  391.                     break;
  392.                   case MN_SELECTED:
  393.                     do_menuitem(xm.msgbuf[3], xm.msgbuf[4]);
  394.                     break;
  395.                 /* etc */
  396.                 }               /* end switch           */
  397.             }                   /* end if (MU_MESAG)    */
  398.         }                       /* end while(1)         */
  399.     }                           /* end multi() function */
  400.     
  401.     As can be seen in the example, this can be much more efficient than
  402.     the usual call to evnt_multi, because it is not necessary to stack
  403.     50-some bytes of info on each loop iteration.  Also, the binding for
  404.     envx_multi is *much* smaller and faster than the one for evnt_multi.
  405.     
  406. ;-------------------------------------------------------------------------
  407. ; winx_get          - Alternate for wind_get
  408. ;-------------------------------------------------------------------------
  409.  
  410.     int winx_get(int whandle, int wfield, GRECT *outrect);
  411.     
  412.     This binding takes the same 2 input parms as wind_get; the window 
  413.     handle, and a value indicating the window info to be returned.  For 
  414.     output, it takes a pointer to a GRECT structure.  The return value is
  415.     the same as for wind_get() (0 indicates error).
  416.     
  417.     Note that the pointer to the output doesn't *have* to be a GRECT 
  418.     pointer, it is more specifically a pointer to 4 contiguous words of 
  419.     storage which will hold the return values.  The only wind_get() 
  420.     functions which return more than a single value all return GRECT type
  421.     output, however.  
  422.     
  423.     If winx_get() is called with a wfield value that implies just one 
  424.     return value (WF_TOP, for example), you must be aware that EIGHT BYTES
  425.     OF MEMORY WILL BE MODIFIED at the location pointed to by the output
  426.     pointer.  (All but the first 2 bytes will be garbage, of course).
  427.     
  428.     Usage example:
  429.     
  430.         GRECT currect;
  431.         
  432.             winx_get(wi_handle, WF_CURRXYWH, &currect);
  433.  
  434. ;-------------------------------------------------------------------------
  435. ; winx_calc         - Alternate for wind_calc
  436. ;-------------------------------------------------------------------------
  437.  
  438.     int winx_calc(int type, kind, in_x, in_y, in_w, in_h, GRECT *outrect);
  439.  
  440.     This binding takes all the same input values as wind_calc, but returns
  441.     the output in a GRECT structure.  Note that although the input xywh
  442.     values are listed as discrete in the definition above, your compiler
  443.     will accept the name of a GRECT as the third parameter, and will 
  444.     stack the four values from the rectangle as discrete parms.
  445.     
  446.     The following example might be used to create a window around an
  447.     object tree...
  448.     
  449.         int   wi_kind  = MOVER | FULLER | CLOSER;
  450.         GRECT workrect;
  451.         GRECT fullrect;
  452.  
  453.         frmx_center(tree, &workrect); 
  454.         winx_calc(WC_BORDER, wi_kind, workrect, &fullrect);
  455.         wi_handle = wind_create(wi_kind, fullrect);
  456.         if (wi_handle >= 0)
  457.             wind_open(wi_handle, fullrect);
  458.  
  459. ;-------------------------------------------------------------------------
  460. ; frmx_center        - Alternate for form_center
  461. ;-------------------------------------------------------------------------
  462.  
  463.     int frmx_center(OBJECT *ptree, GRECT *outrect);
  464.  
  465.     This binding takes a pointer to an object tree (as form_center does),
  466.     and a pointer to a GRECT where the output xywh values will be returned.
  467.     The return value from the function is always 1, as for form_center.
  468.     
  469.     Example:
  470.     
  471.         GRECT treerect;
  472.         
  473.         frmx_center(ptree, &treerect);
  474.         objc_draw(ptree, R_TREE, MAX_DEPTH, treerect);
  475.  
  476. ;-------------------------------------------------------------------------
  477. ; v_gchar - Output a single character via a fast call to v_gtext
  478. ;-------------------------------------------------------------------------
  479.  
  480.     void v_gchar(int vdi_handle, int x, int y, char outchar);
  481.  
  482.     This function generates a fast call to v_gtext to output a single
  483.     character.  It is about half the size of the regular v_gtext binding,
  484.     and will execute **much** faster.  It is useful for things like 
  485.     telecomm programs that must do character-at-a-time output to a window.
  486.     
  487. |   This function is new with v1.5.
  488.  
  489. ;-------------------------------------------------------------------------
  490. ; vdicall - Issue a call to VDI with the specified control/intin/etc.
  491. ;-------------------------------------------------------------------------
  492.  
  493.     int vdicall(control, intin, ptsin, intout, ptsout);
  494.  
  495.     Each of the parameters is a pointer to an array of 16-bit ints.
  496.  
  497.     This function allows you to call VDI functions not directly supported
  498.     by the vdifast bindings library.  Within your program, you set up 
  499.     arrays containing the parameters for the function, and then pass
  500.     pointers to those arrays to this routine.  It will combine the 
  501.     pointers into a VDI parameter block, and issue the VDI trap.
  502.     
  503.     This routine always returns a 16-bit integer which is the contents
  504.     of intout[0].  
  505.     
  506.     You must always supply a non-NULL pointer for control, and the values
  507.     in control must contain everything VDI needs to process the call.
  508.     (IE, opcode, sub-opcode if needed, intin count, ptsin count, and
  509.     extend control info such as the FDB pointers for a blit, if needed).
  510.     You never need to supply the intout or ptsout count values in the
  511.     control array: VDI will fill those in (and will ignore anything you
  512.     put there anyway.)
  513.     
  514.     The other array pointers may be NULL if they are not needed for a 
  515.     given VDI call (ie, if there are no ptsin parms for the call, just
  516.     code NULL for the ptsin pointer).  The intout array is handled a
  517.     little strangely:  if you supply a NULL intout pointer, the vdicall()
  518.     routine allocates a 256-byte intout array on the stack for you.  It
  519.     will return the value from intout[0] as the function return value,
  520.     and discard the rest of the intout array.  This is mainly to provide
  521.     ease-of-use in coding custom bindings which only need a single-word
  522.     return value (ie, success/failure).
  523.     
  524.     As an example, suppose the vro_cpyfm() binding was not supported.
  525.     You could write a macro to implement it, as follows:
  526.     
  527.     #define vro_cpyfm(handle,op,xycoords,srcfdb,dstfdb)        \
  528.             {                                                  \
  529.              int control[11]      = {109, 4, 0, 1, 0, 0};      \
  530.              int temp             = op;                        \  
  531.             control[6]            = handle;                    \    
  532.             *(long*)(&control[7]) = (long)srcfdb;              \
  533.             *(long*)(&control[9]) = (long)dstfdb;              \
  534.             vdicall(control, &temp, xycoords, NULL, NULL);     \
  535.             }
  536.  
  537.     (NOTE: If you are using Sozobon C, the control and temp variables
  538.     in this example would have to be declared as 'static' to avoid a 
  539.     bug in the compiler (at least, as of v1.3) that causes bombs when
  540.     you initialize an auto-class variable declared in a local block.)
  541.  
  542.     There are, of course, other ways to implement functions besides
  543.     coding them as macros -- you can, for example, build your own 
  544.     library of C functions which serve as bindings.  (In fact, I rather 
  545.     hope someone will code up a set of GDOS bindings in this way, and
  546.     that such bindings eventually find their way back to me.  Then I
  547.     could re-do them in assembler and make them part of GemFast.  I
  548.     just don't have any docs on GDOS.)
  549.     
  550.     As an assist to anyone undertaking their own bindings, the following
  551.     is the code that implements this function:
  552.     
  553.     _vdicall:
  554.           .cargs    #8,.control.l,.intin.l,.ptsin.l,.intout.l,.ptsout.l
  555.           link      a6,#-256            ; nice big intout, 'just in case'.
  556.           move.l    a3,-(sp)            ; save this, we use it for intout.
  557.           move.l    .intout(a6),a3      ; get caller-supplied intout ptr.
  558.           move.l    a3,d0               ; test it for NULLness, if it's
  559.           bne.s     .no_local_intout    ; not NULL, continue, else set
  560.           lea       -256(a6),a3         ; up a pointer to our local intout
  561.           clr.w     (a3)                ; array, and blast local intout[0].
  562.     .no_local_intout:
  563.           move.l    .ptsout(a6),-(sp)   ; build vdipb on the stack...
  564.           move.l    a3,-(sp)          
  565.           move.l    .ptsin(a6),-(sp)
  566.           move.l    .intin(a6),-(sp)
  567.           move.l    .control(a6),-(sp)
  568.           move.l    sp,d1               ; load pointer to vdipb
  569.           moveq.l   #$73,d0             ; load vdi function code
  570.           trap      #2                  ; do it.
  571.           move.w    (a3),d0             ; return intout[0] in d0.
  572.           move.l    (sp)+,a3
  573.           unlk      a6
  574.           rts
  575.  
  576. |   This function is new with v1.6.
  577.  
  578. ;-------------------------------------------------------------------------
  579. ; vgd_detect - Detect presence of GDOS on the machine.
  580. ;-------------------------------------------------------------------------
  581.  
  582.     int vgd_detect()
  583.     
  584.     Returns zero if GDOS not present or non-zero if it is present.  Works
  585.     by calling trap #2 with -2 in D0 register, then testing for -2 still
  586.     in the register after the trap.
  587.  
  588. |   This functions is new with v1.7.
  589.  
  590. **************************************************************************
  591. * END OF GEMXTEND DOC
  592. **************************************************************************
  593.  
  594.